package com.philip.demo;

import org.bytedeco.javacpp.DoublePointer;
import org.bytedeco.javacpp.IntPointer;
import org.bytedeco.opencv.opencv_core.*;
import org.bytedeco.opencv.opencv_face.FaceRecognizer;
import org.bytedeco.opencv.opencv_face.FisherFaceRecognizer;
import org.bytedeco.opencv.opencv_face.LBPHFaceRecognizer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.FilenameFilter;
import java.nio.IntBuffer;

import static org.bytedeco.opencv.global.opencv_core.CV_32SC1;
import static org.bytedeco.opencv.global.opencv_imgcodecs.IMREAD_GRAYSCALE;
import static org.bytedeco.opencv.global.opencv_imgcodecs.imread;
import static org.bytedeco.opencv.global.opencv_imgproc.*;

/**
 *  提供人脸识别的接口
 *  人脸识别
 */
public class P_FaceRecognizer {

    private static final Logger LOGGER = LoggerFactory.getLogger(P_FaceRecognizer.class);

    private FaceRecognizer faceRecognizer;

    private static final String DEFAULT_TRAIN_RESULT_PATH="";

    public P_FaceRecognizer() {
        //默认使用Fisher算法
        faceRecognizer = FisherFaceRecognizer.create();
        //默认加载训练好的模型
        this.loadDefaultTrainRetFile();
    }

    public P_FaceRecognizer(String trainingDir) {
       //默认使用Fisher算法
//       faceRecognizer = FisherFaceRecognizer.create();
        faceRecognizer = LBPHFaceRecognizer.create();
       this.retrain(trainingDir);
    }

    /**
     * 加载已经生成好的训练文件
     */
    private void loadDefaultTrainRetFile () {
        File file = new File(DEFAULT_TRAIN_RESULT_PATH);
        if(file.exists()){
            // todo
        }
        else {
            throw new RuntimeException("训练结果文件不存在！");
        }
    }

    /**
     * 带训练的图片必须尺寸需要相同。
     * @param trainingDir
     */
    public void retrain(String trainingDir) {
        LOGGER.info("Running train ... ");
        File root = new File(trainingDir);
        FilenameFilter imgFilter = new FilenameFilter() {
            @Override
            public boolean accept(File dir, String name) {
                name = name.toLowerCase();
                return name.endsWith(".jpg") || name.endsWith(".pgm") || name.endsWith(".png");
            }
        };
        File[] imageFiles = root.listFiles(imgFilter);
        MatVector images = new MatVector(imageFiles.length);
        Mat labels = new Mat(imageFiles.length,1,CV_32SC1);
        IntBuffer labelBuf = labels.createBuffer();
        int counter = 0;
        for (File image : imageFiles) {
            //图片灰度处理
            Mat img = imread(image.getAbsolutePath(),IMREAD_GRAYSCALE);
            //label是用于是否是同一个人的标记。后续就根据比对结果返回。
            int label = Integer.parseInt(image.getName().split("\\-")[0]);
            images.put(counter, img);
            labelBuf.put(counter, label);
            counter++;
        }
        faceRecognizer.train(images,labels);
    }

    /**
     * 识别图像
     * @param targetImage
     * @return
     */
    public int recognize(String targetImage) {
        Mat matImg = imread(targetImage,IMREAD_GRAYSCALE);
        return this.recognize(matImg);
    }

    /**
     * 返回-1 为未识别
     * @param targetImage
     * @return
     */
    public int recognize(Mat targetImage) {
        int labelRet = -1;
        LOGGER.info("Running recoginze ... ");
        int predictedLabel = -1;
        IntPointer label = new IntPointer(1);
        DoublePointer confidence = new DoublePointer(1);
        faceRecognizer.predict(targetImage,label,confidence);
        predictedLabel = label.get(0);
        double confidenceVal=confidence.get(0);
        LOGGER.info("Return recoginze label result : "+ predictedLabel+ " ,confidenceVal: "+confidenceVal);
        if (confidenceVal < 300) {
            labelRet = predictedLabel;
        }
        return labelRet;
    }

    /**
    * 先灰度化在識別
     * @param targetGrayImage 灰度圖
     * @param face_i
     * @return
     */
    public int recognize(Mat targetGrayImage, Rect face_i) {
        Mat targetImage = new Mat();
        Mat roi = new Mat(targetGrayImage, face_i);
        //修剪尺寸與樣本一致
        resize(roi, targetImage, new Size(100, 100));
        return this.recognize(targetImage);
    }

    public void markFace(Mat scr,int predictedLabel,Rect face_i) {
        String box_text = predictedLabel+"_philip ";
        int pos_x = Math.max(face_i.tl().x() - 10, 0);
        int pos_y = Math.max(face_i.tl().y() - 10, 0);
        putText(scr, box_text, new Point(pos_x, pos_y),
                FONT_HERSHEY_PLAIN, 1.0, new Scalar(0, 255, 0, 2.0));
    }

    public class Result{
        int labelRet;
        double confidenceVal;

    }

    public static void main(String[] args) {
        String trainingDir = "D:\\test\\capture\\";
        String targetImg = "D:\\test\\cg.jpg";
        P_FaceRecognizer faceRecognizer = new P_FaceRecognizer(trainingDir);
        int retVal = faceRecognizer.recognize(targetImg);
        System.out.println(retVal);
    }

}
